﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using wt.wine.Application.Common.Interfaces;
using wt.wine.Application.Common.Models;
using wt.wine.Application.ManageDevicetable;
using wt.wine.Domain.DTOModel;
using wt.wine.Domain.Entities;

namespace wt.wine.Infrastructure.Persistence.Repository
{
    public class DevicetableRepository : IDevicetableRepository
    {
        private readonly IApplicationDbContext _dbcontext;
        public DevicetableRepository(IApplicationDbContext dbcontext)
        {
            _dbcontext = dbcontext;
        }


        /// <summary>
        /// 新增设备
        /// </summary>
        /// <param name="model"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<int> AddDeviceTable(devicetable model, CancellationToken cancellationtoken)
        {
            await _dbcontext.devicetable.AddAsync(model, cancellationtoken);
            return await _dbcontext.SaveChangesAsync(cancellationtoken);
        }

        public async Task<int> EditDeviceTable(devicetable model, CancellationToken cancellationtoken)
        {
            _dbcontext.Entry<devicetable>(model).Property("deviceid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("cusdeviceid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("skuid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("capacitythreshold").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("maxcapacity").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("updatetime").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("userpid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("state").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("remark").IsModified = true;
            return await _dbcontext.SaveChangesAsync(cancellationtoken);
        }


        /// <summary>
        /// 修改出酒
        /// </summary>
        /// <param name="model"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<int> EditManageDeviceTable(devicetable model, CancellationToken cancellationtoken)
        {
            //_dbcontext.Entry<devicetable>(model).Property("deviceid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("binduserid").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("updatetime").IsModified = true;
            return await _dbcontext.SaveChangesAsync(cancellationtoken);
        }

        /// <summary>
        /// 出酒 通过登录用户获取出酒数据
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<List<GetDevicetableNameDTO>> GetDevicetableNameByUserId(int userid, CancellationToken cancellationtoken)
        {

            return await (from u in _dbcontext.userdevicetable.AsNoTracking().Where(p => p.binduserid == userid && p.state >= 0)
                          from d in _dbcontext.devicetable.AsNoTracking().Where(p => p.id == u.deviceid && p.state >= 0 && p.skuid > 0).Take(1).DefaultIfEmpty()
                          from s in _dbcontext.skutable.AsNoTracking().Where(p => p.id == d.skuid && p.state >= 0).Take(1).DefaultIfEmpty()
                          where d.id > 0 && s.id > 0
                          select new GetDevicetableNameDTO
                          {
                              id = u != null ? u.deviceid : 0,
                              deviceid = u != null ? d.deviceid : "",
                              cusdeviceid = u != null ? d.cusdeviceid : "",
                              skuid = u != null ? d.skuid : 0,
                              skuName = s != null ? s.name : "",
                              price = s != null ? s.price : 0,
                              unit = s != null ? s.unit : 0
                          }
                      ).ToListAsync(cancellationtoken);


        }

        /// <summary>
        /// 出酒 通过登录用户获取出酒数据
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<List<GetDevicetableNameDTO>> GetDevicetableNameByAdmin(int userid, CancellationToken cancellationtoken)
        {

            return await (from d in _dbcontext.devicetable.AsNoTracking().Where(p => p.binduserid == userid && p.skuid > 0 && p.state >= 0 && p.skuid > 0)
                          from s in _dbcontext.skutable.AsNoTracking().Where(p => p.id == d.skuid && p.state >= 0).Take(1).DefaultIfEmpty()
                          where d.id > 0 && s.id > 0
                          select new GetDevicetableNameDTO
                          {
                              id = d.id,
                              deviceid = d.deviceid,
                              cusdeviceid = d.cusdeviceid,
                              skuid = d.skuid,
                              skuName = s.name,
                              price = s != null ? s.price : 0,
                              unit = s != null ? s.unit : 0
                          }
                      ).ToListAsync(cancellationtoken);


        }

        public async Task<devicetable> GetDevicetableByid(int id, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.id == id && p.state >= 0).FirstOrDefaultAsync(cancellationtoken);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<devicetable> GetDevicetableByid(string device, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.deviceid == device && p.state >= 0).FirstOrDefaultAsync(cancellationtoken);
        }

        /// <summary>
        /// 设备列表
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<PaginatedList<GetDevicetableListByUserIdDTO>> GetDeviceListByUserId(int userid, string device, int pageIndex, int pageSize, CancellationToken cancellationtoken)
        {
            var query = (from d in _dbcontext.devicetable.AsNoTracking().Where(p => p.binduserid == userid && p.state >= 0)
                         from skuname in _dbcontext.skutable.AsNoTracking().Where(x => x.id == d.skuid).Select(p => p.name).DefaultIfEmpty()
                         where (string.IsNullOrWhiteSpace(device) || (!string.IsNullOrWhiteSpace(device) && ((d.currentcapacity + skuname).Contains(device))))
                         orderby (d.currentcapacity<=d.capacitythreshold?1:2) ascending,d.id descending
                         select new GetDevicetableListByUserIdDTO()
                         {
                             id = d.id,
                             capacitythreshold = d.capacitythreshold,
                             cusdeviceid = d.cusdeviceid,
                             deviceid = d.deviceid,
                             maxcapacity = d.maxcapacity,
                             remark = d.remark,
                             skuid = d.skuid,
                             skuName = skuname,
                             currentcapacity=d.currentcapacity
                         });

            return await PaginatedList<GetDevicetableListByUserIdDTO>.CreateAsync(query, pageIndex, pageSize, cancellationtoken);
        }

        /// <summary>
        /// 判断当前设备号是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <param name="device"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<int> GetDeviceCount(int id, string device, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.id != id && p.deviceid == device && p.state >= 0).CountAsync(cancellationtoken);
        }

        /// <summary>
        /// 获取当前经销商设备量
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<int> GetCountByUserId(int userid, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.binduserid == userid && p.state >= 0).CountAsync(cancellationtoken);
        }

        /// <summary>
        /// 设备加酒获取设备列表
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<List<GetDeviceNameByAddWineDTO>> GetDeviceListByAddWine(int userid, CancellationToken cancellationtoken)
        {
            return await (from d in _dbcontext.devicetable.AsNoTracking()
                          join s in _dbcontext.skutable.AsNoTracking() on d.skuid equals s.id
                          where d.binduserid == userid && d.state >= 0 && s.state >= 0 && d.skuid > 0
                          select new GetDeviceNameByAddWineDTO()
                          {
                              id = d.id,
                              deviceid = d.deviceid,
                              currentcapacity = d.currentcapacity,
                              cusdeviceid = d.cusdeviceid,
                              maxcapacity = d.maxcapacity,
                              skuid = d.skuid,
                              name = s != null ? s.name : ""
                          }
                          ).ToListAsync(cancellationtoken);
        }

        public GetDeviceNameByAddWineDTO GetDeviceListByAddWine(int userid, int did, CancellationToken cancellationtoken)
        {
            return (from d in _dbcontext.devicetable.AsNoTracking().Where(d => d.id == did)
                    join s in _dbcontext.skutable.AsNoTracking() on d.skuid equals s.id
                    where d.binduserid == userid && d.state >= 0 && s.state >= 0 && d.skuid > 0
                    select new GetDeviceNameByAddWineDTO()
                    {
                        id = d.id,
                        deviceid = d.deviceid,
                        currentcapacity = d.currentcapacity,
                        cusdeviceid = d.cusdeviceid,
                        maxcapacity = d.maxcapacity,
                        skuid = d.skuid,
                        name = s != null ? s.name : ""
                    }).FirstOrDefault();
        }

        /// <summary>
        /// 修改设备当前酒量
        /// </summary>
        /// <param name="model"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task EditDevicecapacitythreshold(devicetable model, CancellationToken cancellationtoken)
        {
            _dbcontext.Entry<devicetable>(model).Property("currentcapacity").IsModified = true;
            await _dbcontext.SaveChangesAsync(cancellationtoken);
        }

        /// <summary>
        /// 【经销商】缺酒补货提醒
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<PaginatedList<GetDeviceLessWineDTO>> GetDeviceLessWineList(int userid, int pageIndex, int pageSize, CancellationToken cancellationtoken)
        {
            var query = from d in _dbcontext.devicetable.AsNoTracking().Where(p => p.binduserid == userid && p.state >= 0)
                        from c in _dbcontext.configtable.AsNoTracking().Where(p => p.binduserid == d.binduserid && p.state >= 0).Select(p => p.capacitythreshold).Take(1).DefaultIfEmpty()
                        orderby d.currentcapacity ascending
                        select new GetDeviceLessWineDTO()
                        {
                            id = d.id,
                            deviceid = d.deviceid,
                            currentcapacity = d.currentcapacity,
                            cusdeviceid = d.cusdeviceid,
                            remark = d.remark,
                            skuid = d.skuid,
                            skuname = _dbcontext.skutable.AsNoTracking().Where(p => p.id == d.skuid && p.state >= 0).Select(p => p.name).Take(1).FirstOrDefault(),
                            updatetime = d.updatetime,
                            deviceState = d.currentcapacity - (c > 0 ? c : d.currentcapacity) > 0 ? 1 : 0
                        };

            return await PaginatedList<GetDeviceLessWineDTO>.CreateAsync(query, pageIndex, pageSize, cancellationtoken);
        }

        /// <summary>
        /// 通过id获取设备信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="userid"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<GetDeviceByIdDTO> GetDeviceById(int id, int userid, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.id == id && (p.binduserid == userid || p.userid == userid) && p.state >= 0).Select(p => new GetDeviceByIdDTO() { id = p.id, capacitythreshold = p.capacitythreshold, cusdeviceid = p.cusdeviceid, deviceid = p.deviceid, maxcapacity = p.maxcapacity, remark = p.remark, skuid = p.skuid, skuName = _dbcontext.skutable.AsNoTracking().Where(x => x.id == p.skuid && p.state >= 0).Select(p => p.name).FirstOrDefault() + "" }).FirstOrDefaultAsync(cancellationtoken);
        }

        public async Task<List<devicetable>> GetDevicetableListByIds(List<int> list_ids, int userid, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => list_ids.Contains(p.id) && p.binduserid == userid && p.state >= 0).ToListAsync(cancellationtoken);
        }


        public async Task<List<GetDeviceByAddUserDTO>> GetDeviceByAddUser(int userid, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => p.binduserid == userid && p.state >= 0 && p.skuid > 0).Select(p => new GetDeviceByAddUserDTO()
            {
                id = p.id,
                cusdeviceid = p.cusdeviceid,
                deviceid = p.deviceid,
                skuname = _dbcontext.skutable.AsNoTracking().Where(x => x.id == p.skuid && x.state >= 0).Select(p => p.name).FirstOrDefault()
            }).ToListAsync(cancellationtoken);
        }

        /// <summary>
        /// 回调修改设备状态
        /// </summary>
        /// <param name="model"></param>
        /// <param name="oow"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task EditDeviceState(devicetable model,int oow, CancellationToken cancellationtoken)
        {
            _dbcontext.Entry<devicetable>(model).Property("state").IsModified = true;
            _dbcontext.Entry<devicetable>(model).Property("updatetime").IsModified = true;
            if (oow > 0)
            {
                _dbcontext.Entry(model).Property(nameof(model.currentcapacity)).IsModified = true;
            }
            await _dbcontext.SaveChangesAsync(cancellationtoken);
        }

        /// <summary>
        /// 获取设备
        /// </summary>
        /// <param name="listdevice"></param>
        /// <param name="cancellationtoken"></param>
        /// <returns></returns>
        public async Task<List<devicetable>> GetDeviceList(List<string> listdevice, DateTime dt_now, CancellationToken cancellationtoken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(p => listdevice.Contains(p.deviceid) && p.state >= 0 && p.updatetime > dt_now).ToListAsync(cancellationtoken);
        }

        public async Task<PaginatedList<GetManageDeviceListDTO>> GetManageDeviceList(int userid, int pageIndex, int pageSize, CancellationToken cancellationtoken)
        {
            var query = from d in _dbcontext.devicetable.AsNoTracking()
                        where d.userid == userid && d.state >= 0
                        orderby d.updatetime descending
                        select new GetManageDeviceListDTO()
                        {
                            id = d.id,
                            deviceid = d.deviceid,
                            isBindUser = d.binduserid > 0 ? 1 : 0,
                            account = _dbcontext.usertable.AsNoTracking().Where(p => p.id == d.binduserid).Select(p => p.account).FirstOrDefault(),
                            state = d.state
                        };

            return await PaginatedList<GetManageDeviceListDTO>.CreateAsync(query, pageIndex, pageSize, cancellationtoken);
        }

        public async Task<GetDeviceModelByIdDTO> GetDeviceModelById(int userid, int id, CancellationToken cancellationtoken)
        {
            return await (from d in _dbcontext.devicetable.AsNoTracking().Where(p => p.userid == userid && p.id == id && p.state >= 0)
                          from u in _dbcontext.usertable.AsNoTracking().Where(p => p.id == d.binduserid && p.state >= 0)
                          select new GetDeviceModelByIdDTO()
                          {
                              id = d.id,
                              deviceid = d.deviceid,
                              cusdeviceid = d.cusdeviceid,
                              account = u != null ? u.account : "",
                              name = u != null ? u.name : "",
                              address = u != null ? u.address : "",
                              isBind = d.binduserid > 0 && u != null ? 1 : 0,
                              state = d.state,
                              skuName = _dbcontext.skutable.AsNoTracking().Where(p => p.id == d.skuid && p.state >= 0).Select(p => p.name).FirstOrDefault()
                          }).FirstOrDefaultAsync(cancellationtoken);
        }

        public async Task<int> GetNeedAddWineCount(int userid,CancellationToken cancellationToken)
        {
            return await _dbcontext.devicetable.AsNoTracking().Where(d => d.binduserid == userid && d.state >= 0 && d.currentcapacity <= d.capacitythreshold).CountAsync();
        }
    }
}
